/**
 * 
 */
package com.fastwire.carriere.rad.util;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

import com.fastwire.carriere.common.util.CommonLogger;

/**
 * @author Jun Created on 20120302
 */
public class NetworkUtil
{
    /*
     * private enum OS_TYPE { WIN, LINUX, INVALID; } private static OS_TYPE osType = OS_TYPE.LINUX;
     * 
     * static { String os = System.getProperty("os.name").toLowerCase(); if ((os.indexOf("win") >=
     * 0)) { osType = OS_TYPE.WIN; } else if (os.indexOf("nix") >= 0 || os.indexOf("nux") >= 0) { //
     * linux or unix osType = OS_TYPE.LINUX; } }
     */

    // simple check: ip = 192.168.0.1
    public static boolean ipv4Check(String ip)
    {
        return ip.matches("^[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}");
    }

    // ip should be valid
    public static long ipv4toInt(String ip)
    {
        if (!ipv4Check(ip))
        {
            return 0;
        }

        String[] tmp = ip.split("\\.");

        return (Long.parseLong(tmp[0]) << 24) + (Integer.parseInt(tmp[1]) << 16)
                + (Integer.parseInt(tmp[2]) << 8) + Integer.parseInt(tmp[3]);

    }

    // converting an existing String to Integer
    public static Long ipToInt(String addr)
    {
        String[] addrArray = addr.split("\\.");

        long num = 0;
        for (int i = 0; i < addrArray.length; i++)
        {

            int power = 3 - i;
            num += ((Integer.parseInt(addrArray[i]) % 256 * Math.pow(256, power)));
        }

        return num;
    }

    public static String intToIp(int i)
    {
        return ((i >> 24) & 0xFF) + "." + ((i >> 16) & 0xFF) + "." + ((i >> 8) & 0xFF) + "."
                + (i & 0xFF);
    }

    //
    // InetAddress address = InetAddress.getByName(ip);
    // boolean status = address.isReachable(timeout);
    //
    public static boolean isReachable(String ip, int timeout)
    {
        if(!ipv4Check(ip))
        {
            return false;
        }
        
        boolean bRst = false;

        try
        {
            Process p = Runtime.getRuntime().exec("ping -n 1 " + ip);
            ;
            /*
             * // 1 can be bigger, but affect the performance if (osType == OS_TYPE.WIN) { p =
             * Runtime.getRuntime().exec("cmd /c ping -n 1 -w " + timeout + " " + ip); } else { p =
             * Runtime.getRuntime().exec("/bin/ping -n 1 -w " + timeout + " " + ip); } //p.wait();
             */

            BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()));
            String temp = null;
            StringBuffer strBuffer = new StringBuffer();
            while ((temp = (in.readLine())) != null)
            {
                strBuffer.append(temp);
            }

            String resp = strBuffer.toString();
            // System.out.println(strBuffer); .*\\(\\d?\\d% loss\\).*
            // if (strBuffer.toString().matches(".*\\(\\d?\\d% loss\\).*")) {
            if (resp.matches(".*Destination host unreachable.*"))
            {
                bRst = false;
            }
            else if (resp.matches(".*\\(\\d?\\d% loss\\).*"))
            {
                bRst = true;
                // System.out.println("OK");
            }
            else
            {
                System.out.printf("%s could not be connected.%n", ip);
            }
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
        catch (Exception e)
        {
            e.printStackTrace();
            System.out.printf("Unknown ip: %s%n", ip);
        }

        return bRst;
    }
    
    
    public static List<String> getAllIPsBySubnet(String ipSubnet)
    {
        List<String> ipList = new ArrayList<String>();
        
        // means only a IP: 192.168.10.0
        if (0 < ipSubnet.indexOf("/") && NetworkUtil.ipv4Check(ipSubnet))
        {
            ipList.add(ipSubnet);

            return ipList;
        }

        // for IP/Subnet
        // ipSubnet = "129.9.0.20/0"; // 1.2.3.4/24
        String[] ipSubnetPair = ipSubnet.split("\\/"); // ipSubnet.split("/");

        // IpAddress ipaddr = new IpAddress(strIp); // 192.168.10.0
        // long valIP1 = NetworkUtil.ipv4toInt(ipSubnetPair[0]);
        long valIP = NetworkUtil.ipToInt(ipSubnetPair[0]);
        int iSubnet = Integer.parseInt(ipSubnetPair[1]); // 24 , 0 ???

        iSubnet = 32 - iSubnet;
        // int subnet = ((int)Math.pow(2, 32)-1) << iSubnet; // 255.255.255.0
        long subnet = (0xFFFFFFFFL << iSubnet) & 0xFFFFFFFFL;

        long iipStart = valIP & subnet;
        final long iipEnd = valIP | (~subnet & 0xFFFFFFFFL);
        
        iipStart += 1;   // cannot all 0;
        for (; iipStart < iipEnd; ++iipStart)   // iipEnd should subtract 1 
        {
            // String strCurrentIP = String.valueOf(iipStart);
            String strCurrentIP = NetworkUtil.intToIp((int) iipStart);
            if (NetworkUtil.ipv4Check(strCurrentIP))
            {
                CommonLogger.info(null, "Ip is: " + strCurrentIP);

                // InetAddress ad = InetAddress.getByName(strCurrentIP); //
                // "192.168.1.119 ");
                ipList.add(strCurrentIP);
            }
            else
            {
                CommonLogger.info(null, "ip is not correct: " + strCurrentIP);
            }
        }

        return ipList;
    }
}
